#include "Hash.h"

#include <string.h>

#include <vector>
#include <iostream>

//逻辑函数如下
/*
∧：按位“与”
!：按位“补”
⊕：按位“异或”
Sn：循环右移n个bit
Rn：右移n个bit
*/
#define ROTRIGHT(a,b) (((a) >> (b)) | ((a) << (32-(b)))) 			//循环右移
#define MAJ(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z)))	    //Ma(x,y,z)=(x∧y)⊕(x∧z)⊕(y∧z)
#define EP0(x) (ROTRIGHT(x,2) ^ ROTRIGHT(x,13) ^ ROTRIGHT(x,22))	//Σ0(x)=S2(x)⊕S13(x)⊕S22(x)
#define EP1(x) (ROTRIGHT(x,6) ^ ROTRIGHT(x,11) ^ ROTRIGHT(x,25))	//Σ1(x)=S6(x)⊕S11(x)⊕S25(x)
#define SIG0(x) (ROTRIGHT(x,7) ^ ROTRIGHT(x,18) ^ ((x) >> 3))		//σ0(x)=S7(x)⊕S18(x)⊕R3(x)
#define SIG1(x) (ROTRIGHT(x,17) ^ ROTRIGHT(x,19) ^ ((x) >> 10))		//σ1(x)=S17(x)⊕S19(x)⊕R10(x)
#define CH(x,y,z) (((x) & (y)) ^ (~(x) & (z)))		//Ch(x,y,z)=(x∧y)⊕(¬x∧z)







// 初始化SHA-256上下文
void SHA256::sha256_init(SHA256_CTX* ctx) {
    ctx->datalen = 0;
    ctx->bitlen = 0;
    ctx->state[0] = 0x6a09e667;
    ctx->state[1] = 0xbb67ae85;
    ctx->state[2] = 0x3c6ef372;
    ctx->state[3] = 0xa54ff53a;
    ctx->state[4] = 0x510e527f;
    ctx->state[5] = 0x9b05688c;
    ctx->state[6] = 0x1f83d9ab;
    ctx->state[7] = 0x5be0cd19;
}


// 对一个长度为512bit的数据块进行操作，将其转换成Hash值
void SHA256::sha256_transform(SHA256_CTX* ctx, const HASHBYTE data[]) {
    // 定义变量用于存储中间状态
    HASHWORD a, b, c, d, e, f, g, h, i, j, t1, t2, m[64]; // m 表示64个32位字

    // 初始化前16个字
    for (i = 0, j = 0; i < 16; ++i, j += 4)
        m[i] = (data[j] << 24) | (data[j + 1] << 16) | (data[j + 2] << 8) | (data[j + 3]); // 将数据块划分为16个32位字

    // 计算后续的48个字
    for (; i < 64; ++i)
        m[i] = SIG1(m[i - 2]) + m[i - 7] + SIG0(m[i - 15]) + m[i - 16]; // 使用递推公式计算剩余字

    // 初始化压缩函数的初始值
    a = ctx->state[0];
    b = ctx->state[1];
    c = ctx->state[2];
    d = ctx->state[3];
    e = ctx->state[4];
    f = ctx->state[5];
    g = ctx->state[6];
    h = ctx->state[7];

    // SHA-256 主循环
    for (i = 0; i < 64; ++i) {
        t1 = h + EP1(e) + CH(e, f, g) + k[i] + m[i]; // 计算T1
        t2 = EP0(a) + MAJ(a, b, c);                  // 计算T2
        h = g;                                       // 更新H
        g = f;                                       // 更新G
        f = e;                                       // 更新F
        e = d + t1;                                  // 更新E
        d = c;                                       // 更新D
        c = b;                                       // 更新C
        b = a;                                       // 更新B
        a = t1 + t2;                                 // 更新A
    }

    // 更新上下文中的状态值
    ctx->state[0] += a;
    ctx->state[1] += b;
    ctx->state[2] += c;
    ctx->state[3] += d;
    ctx->state[4] += e;
    ctx->state[5] += f;
    ctx->state[6] += g;
    ctx->state[7] += h;
}

// 数据更新
void SHA256::sha256_update(SHA256_CTX* ctx, const HASHBYTE data[], size_t len) {
    for (size_t i = 0; i < len; ++i) {
        ctx->data[ctx->datalen++] = data[i];
        if (ctx->datalen == 64) {
            sha256_transform(ctx, ctx->data);
            ctx->bitlen += 512;
            ctx->datalen = 0;
        }
    }
}





void SHA256::sha256_final(SHA256_CTX* ctx, HASH_VALUE& hash) {
    HASHWORD i = ctx->datalen;

    ctx->data[i++] = 0x80;
    if (i < 56) {
        memset(ctx->data + i, 0, 56 - i);
    }
    else {
        memset(ctx->data + i, 0, 64 - i);
        sha256_transform(ctx, ctx->data);
        memset(ctx->data, 0, 56);
    }

    ctx->bitlen += ctx->datalen * 8;
    ctx->data[63] = (HASHBYTE)(ctx->bitlen);
    ctx->data[62] = (HASHBYTE)(ctx->bitlen >> 8);
    ctx->data[61] = (HASHBYTE)(ctx->bitlen >> 16);
    ctx->data[60] = (HASHBYTE)(ctx->bitlen >> 24);
    ctx->data[59] = (HASHBYTE)(ctx->bitlen >> 32);
    ctx->data[58] = (HASHBYTE)(ctx->bitlen >> 40);
    ctx->data[57] = (HASHBYTE)(ctx->bitlen >> 48);
    ctx->data[56] = (HASHBYTE)(ctx->bitlen >> 56);
    sha256_transform(ctx, ctx->data);

    for (i = 0; i < 4; ++i) {
        hash[i] = (ctx->state[0] >> (24 - i * 8)) & 0xFF;
        hash[i + 4] = (ctx->state[1] >> (24 - i * 8)) & 0xFF;
        hash[i + 8] = (ctx->state[2] >> (24 - i * 8)) & 0xFF;
        hash[i + 12] = (ctx->state[3] >> (24 - i * 8)) & 0xFF;
        hash[i + 16] = (ctx->state[4] >> (24 - i * 8)) & 0xFF;
        hash[i + 20] = (ctx->state[5] >> (24 - i * 8)) & 0xFF;
        hash[i + 24] = (ctx->state[6] >> (24 - i * 8)) & 0xFF;
        hash[i + 28] = (ctx->state[7] >> (24 - i * 8)) & 0xFF;
    }
}



void SHA256::computeHash(const std::vector<uint8_t>& message_bytes, HASH_VALUE& hash){
    SHA256_CTX ctx;
    // 初始化上下文和数据缓冲区
    sha256_init(&ctx);
    sha256_update(&ctx, message_bytes.data(), message_bytes.size());
    // 计算哈希值并输出结果
    sha256_final(&ctx, hash);
}

#undef ROTRIGHT
#undef MAJ
#undef EP0
#undef EP1
#undef SIG0
#undef SIG1
#undef CH



#define ROTRIGHT(x, n) (((x) >> (n)) | ((x) << (64 - (n))))
#define CH(x, y, z) (((x) & (y)) ^ (~(x) & (z)))
#define MAJ(x, y, z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z)))
#define EP0(x) (ROTRIGHT(x,28) ^ ROTRIGHT(x,34) ^ ROTRIGHT(x,39))
#define EP1(x) (ROTRIGHT(x,14) ^ ROTRIGHT(x,18) ^ ROTRIGHT(x,41))
#define SIG0(x) (ROTRIGHT(x,1) ^ ROTRIGHT(x,8) ^ ((x) >> 7))
#define SIG1(x) (ROTRIGHT(x,19) ^ ROTRIGHT(x,61) ^ ((x) >> 6))



void SHA512::sha512_init(SHA512_CTX* ctx) {
    ctx->datalen = 0;
    ctx->bitlen_low = 0;
    ctx->bitlen_high = 0;
    ctx->state[0] = 0x6a09e667f3bcc908;
    ctx->state[1] = 0xbb67ae8584caa73b;
    ctx->state[2] = 0x3c6ef372fe94f82b;
    ctx->state[3] = 0xa54ff53a5f1d36f1;
    ctx->state[4] = 0x510e527fade682d1;
    ctx->state[5] = 0x9b05688c2b3e6c1f;
    ctx->state[6] = 0x1f83d9abfb41bd6b;
    ctx->state[7] = 0x5be0cd19137e2179;
}

void SHA512::sha512_transform(SHA512_CTX* ctx, const HASHBYTE data[]) {
    uint64_t a, b, c, d, e, f, g, h, t1, t2;
    uint64_t m[80];

    for (int i = 0; i < 16; i++) {
        m[i] = ((uint64_t)data[i*8] << 56) | ((uint64_t)data[i*8+1] << 48) |
               ((uint64_t)data[i*8+2] << 40) | ((uint64_t)data[i*8+3] << 32) |
               ((uint64_t)data[i*8+4] << 24) | ((uint64_t)data[i*8+5] << 16) |
               ((uint64_t)data[i*8+6] << 8)  | ((uint64_t)data[i*8+7]);
    }

    for (int i = 16; i < 80; i++) {
        m[i] = SIG1(m[i-2]) + m[i-7] + SIG0(m[i-15]) + m[i-16];
    }

    a = ctx->state[0]; b = ctx->state[1]; c = ctx->state[2]; d = ctx->state[3];
    e = ctx->state[4]; f = ctx->state[5]; g = ctx->state[6]; h = ctx->state[7];

    for (int i = 0; i < 80; i++) {
        t1 = h + EP1(e) + CH(e,f,g) + k[i] + m[i];
        t2 = EP0(a) + MAJ(a,b,c);
        h = g; g = f; f = e; e = d + t1;
        d = c; c = b; b = a; a = t1 + t2;
    }

    ctx->state[0] += a; ctx->state[1] += b; ctx->state[2] += c; ctx->state[3] += d;
    ctx->state[4] += e; ctx->state[5] += f; ctx->state[6] += g; ctx->state[7] += h;
}

void SHA512::sha512_update(SHA512_CTX* ctx, const HASHBYTE data[], size_t len) {
    size_t index = 0;
    while (index < len) {
        size_t copy_len = std::min(len - index, (size_t)(128 - ctx->datalen));
        memcpy(ctx->data + ctx->datalen, data + index, copy_len);
        ctx->datalen += copy_len;
        index += copy_len;

        if (ctx->datalen == 128) {
            sha512_transform(ctx, ctx->data);
            uint64_t add_low = 1024;
            ctx->bitlen_low += add_low;
            if (ctx->bitlen_low < add_low) ctx->bitlen_high++;
            ctx->datalen = 0;
        }
    }
}

void SHA512::sha512_final(SHA512_CTX* ctx, HASH_VALUE_64& hash) {
    uint32_t i = ctx->datalen;
    ctx->data[i++] = 0x80;

    if (i > 112) {
        memset(ctx->data + i, 0, 128 - i);
        sha512_transform(ctx, ctx->data);
        i = 0;
    }

    memset(ctx->data + i, 0, 112 - i);

    uint64_t total_bits_low = ctx->bitlen_low + ctx->datalen * 8;
    uint64_t total_bits_high = ctx->bitlen_high;
    if (total_bits_low < ctx->bitlen_low) total_bits_high++;

    for (int j = 0; j < 8; j++) {
        ctx->data[120 + j] = (total_bits_low >> (56 - j*8)) & 0xFF;
        ctx->data[112 + j] = (total_bits_high >> (56 - j*8)) & 0xFF;
    }

    sha512_transform(ctx, ctx->data);

    for (i = 0; i < 8; i++) {
        hash[i*8 + 0] = (ctx->state[i] >> 56) & 0xFF;
        hash[i*8 + 1] = (ctx->state[i] >> 48) & 0xFF;
        hash[i*8 + 2] = (ctx->state[i] >> 40) & 0xFF;
        hash[i*8 + 3] = (ctx->state[i] >> 32) & 0xFF;
        hash[i*8 + 4] = (ctx->state[i] >> 24) & 0xFF;
        hash[i*8 + 5] = (ctx->state[i] >> 16) & 0xFF;
        hash[i*8 + 6] = (ctx->state[i] >> 8) & 0xFF;
        hash[i*8 + 7] = ctx->state[i] & 0xFF;
    }
}

void SHA512::computeHash64(const BYTE_VECTOR& message_bytes, HASH_VALUE_64& hash) {
    SHA512_CTX ctx;
    sha512_init(&ctx);
    sha512_update(&ctx, message_bytes.data(), message_bytes.size());
    sha512_final(&ctx, hash);
}
